package cn.toma.wx.core;

import cn.toma.common.utils.StringUtils;
import cn.toma.core.exception.GlobalException;
import cn.toma.core.result.CodeMsg;
import cn.toma.wx.vo.Code2SessionVo;
import cn.toma.wx.vo.WxUserInfo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * @author zqx
 * @version 1.0.0
 * @ClassName AppletsConfig.java
 * @Description
 * @createTime 2019年09月19日 14:56:00
 */
@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "tencent.weixin.applets")
public class AppletsComponent
{
	/**
	 * 小程序ID
	 */
	private String appId;
	/**
	 * 秘钥
	 */
	private String secretId;
	/**
	 * 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
	 */
	private String authCode2Session;
	/**
	 * 获取 ACCESS_TOKEN API
	 */
	private  String accessTokenUrl;
	/**
	 * 获取小程序二维码 API
	 */
	private String getUnlimited;



	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private RedisTemplate<Object, Object> redisTemplate;

	@Autowired
	private WxAes wxAes;

	/**
	 * 获取微信小程序 session_key 和 openid
	 *
	 * @param code login code
	 * @return errcode session_key openid
	 */
	public Code2SessionVo getCode2Session(String code)
	{
		try {
			String apiLink = authCode2Session + code;
			ResponseEntity<String> forEntity = restTemplate.getForEntity(apiLink, String.class);
			JSONObject jsonObject = JSONObject.fromObject(forEntity.getBody());
			log.debug("{}",jsonObject);
			String openid = jsonObject.getString("openid");
			String sessionKey = jsonObject.getString("session_key");
			String unionid = "";
			if (jsonObject.has("unionid")) {
				unionid = jsonObject.getString("unionid");
			}
			Code2SessionVo code2SessionVo = new Code2SessionVo(openid, sessionKey, unionid);
			return code2SessionVo;
		} catch (Exception e) {
			throw new GlobalException(CodeMsg.FAIL);
		}

	}

	/**
	 * 获取用户详细信息
	 *
	 * @param encryptedData
	 * @param sessionKey
	 * @param iv
	 * @return
	 */
	public WxUserInfo getUserInfo(String encryptedData, String sessionKey, String iv)
	{
		try {
			encryptedData = encryptedData.replaceAll(" ", "+");
			iv = iv.replaceAll(" ", "+");
			byte[] resultByte = wxAes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
			if (null != resultByte && resultByte.length > 0) {
				String userInfo = new String(resultByte, StandardCharsets.UTF_8);
				JSONObject jsonObject = JSONObject.fromObject(userInfo);
				log.debug("{}", jsonObject);
				WxUserInfo wxUserInfo = new WxUserInfo();
				wxUserInfo.setAvatarUrl(jsonObject.getString("avatarUrl"));
				wxUserInfo.setOpenId(jsonObject.getString("openId"));
				wxUserInfo.setNickName(jsonObject.getString("nickName"));
				wxUserInfo.setGender(jsonObject.getString("gender"));
				wxUserInfo.setCity(jsonObject.getString("city"));
				wxUserInfo.setProvince(jsonObject.getString("province"));
				wxUserInfo.setCountry(jsonObject.getString("country"));
				if (jsonObject.has("unionId")){
					wxUserInfo.setUnionId(jsonObject.getString("unionId"));
				}
				return wxUserInfo;
			}
			return null;
		} catch (Exception e) {
			throw new GlobalException(CodeMsg.DECRYPT_FAIL);
		}
	}

	/**
	 * 通用 微信小程序信息解密
	 * @param encryptedData 被加密的数据
	 * @param sessionKey 通过wx.login() 返回的code 后台获取 openId  sessionKey
	 * @param iv 加密偏移量
	 * @return
	 */
	public JSONObject decrypt(String encryptedData, String sessionKey, String iv)
	{
		try {
			encryptedData = encryptedData.replaceAll(" ", "+");
			iv = iv.replaceAll(" ", "+");
			byte[] resultByte = wxAes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
			if (null != resultByte && resultByte.length > 0) {
				String userInfo = new String(resultByte, StandardCharsets.UTF_8);
				JSONObject jsonObject = JSONObject.fromObject(userInfo);
				log.debug("加密数据:{}", jsonObject);
				return jsonObject;
			}
			return null;
		} catch (Exception e) {
			throw new GlobalException(CodeMsg.DECRYPT_FAIL);
		}
	}

	/**
	 * @return 获取 ACCESS_TOKEN
	 */
	public String getAccessTokenJson()
	{
		String accessTokenKey = "WX:ACCESS_TOKEN";
		if (redisTemplate.hasKey(accessTokenKey)) {
			String access = (String) redisTemplate.opsForValue().get(accessTokenKey);
			return access;
		}
		ResponseEntity<String> forEntity = restTemplate.getForEntity(accessTokenUrl, String.class);

		JSONObject jsonObject = JSONObject.fromObject(forEntity.getBody());
		String accessToken = jsonObject.getString("access_token");
		if (StringUtils.isNotEmpty(accessToken)) {
			redisTemplate.opsForValue().set(accessTokenKey, accessToken, 110, TimeUnit.MINUTES);
			return accessToken;
		}
		return null;
	}

	/**
	 * 请求获取小程序二维码
	 *
	 * @param scene 参数
	 */
	public String getQrCode(String scene) throws IOException
	{
		String accessTokenJson = getAccessTokenJson();
		String replaceAll = getUnlimited + accessTokenJson;
		JSONObject json = new JSONObject();
		json.put("scene", scene);
		json.put("page", "pages/index/main");
		json.put("width", 280);
		json.put("auto_color", true);
		json.put("line_color", "{\"r\":223,\"g\":16,\"b\":16}");
		json.put("is_hyaline", true);
		ResponseEntity<Resource> entity = restTemplate.postForEntity(replaceAll, json, Resource.class);
		InputStream in = null;
		in = entity.getBody().getInputStream();
		ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
		int ch;
		while ((ch = in.read()) != -1) {
			bytestream.write(ch);
		}
		log.debug("{}",bytestream);
		boolean errmsg = bytestream.toString().contains("errmsg");
		if (errmsg){
			throw new GlobalException(CodeMsg.QRCODE_FAIL);
		}

		byte[] program = bytestream.toByteArray();
		BASE64Encoder encoder = new BASE64Encoder();
		String binary = encoder.encodeBuffer(program).trim();
		log.debug("获取小程序二维码流:{}", binary);
		return binary;
	}


}
